package com.conceal.client.utils;


import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Hashtable;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.module.SimpleModule;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.conceal.client.utils.BigIntegerSerializerProvider;
import com.conceal.client.utils.DateSerializerProvider;
import com.conceal.client.utils.LongSerializerProvider;


/**
 * 工具类 - Spring
 */

@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    private static Hashtable<String, Object> beanCache=new Hashtable<String, Object>();

    private static Pattern oldBrowser=Pattern.compile("MSIE (6|7)");

    private static Pattern pKeyVal=Pattern.compile("(\\x22|\\\\\\x22|[\\s]{0,})([_a-zA-Z0-9]+)(\\1):[\\x20\\t]{0,}([\\x22\\\\\\x22]{0,})(?!\\{|\\\")(.*?)(\\4)(\\s|,|})", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);


    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtil.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 取当前的request对象
     * @return
     */
    public static HttpServletRequest getRequest(){
        ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest req = sra.getRequest();
        return req;
    }

    /**
     * 根据Bean名称获取实例
     *
     * @param name
     *            Bean注册名称
     *
     * @return bean实例
     *
     * @throws BeansException
     */
    public static Object getBean(String name) throws BeansException {
        Object ret=beanCache.get(name); // 先从缓存取
        if(ret==null){ // 缓存中没有
            if(applicationContext!=null){
                ret=applicationContext.getBean(name); // 从系统环境中取
            }
            if(ret!=null){ // 取到了
                beanCache.put(name, ret); // 缓存
            }
        }
        return ret;
    }

    /**
     * 取JdbcTemplate
     * @return
     * @throws BeansException
     */
    public static JdbcTemplate getJdbcTemplate(String database) throws BeansException {
        return (JdbcTemplate)applicationContext.getBean(String.format("jdbcTemplate-%s", database));
    }

    /**
     * 取事务模板
     * @param database
     * @return
     * @throws BeansException
     */
    public static TransactionTemplate getTransactionTemplate(String database) throws BeansException {
        return (TransactionTemplate)applicationContext.getBean(String.format("transactionTemplate-%s", database));
    }

    /**
     * 取properties配置
     * @param propertiesBeanName
     * @param key
     * @return
     */
    public static String getConfig(String propertiesBeanName, String key){
        String ret=null;
        Properties prop=(Properties)SpringUtil.getBean(propertiesBeanName);
        if(prop!=null){
            ret=prop.getProperty(key);
        }
        return ret;
    }

    /**
     * 取cookie
     * @param cookieName
     * @return
     */
    public static String getCookie(String cookieName){
        String ret="";
        Cookie[] list=getRequest().getCookies();
        if(list!=null){
            for(int i=0; i<list.length; i++){
                Cookie cookie=list[i];
                if(cookie.getName().equals(cookieName)){
                    ret=cookie.getValue();
                }
            }
        }
        return ret;
    }

    /**
     * 设置cookie
     * @param response
     * @param cookieName
     * @param value
     * @param liveSeconds
     */
    public static void setCookie(HttpServletResponse response, String cookieName, String value, int liveSeconds){
        final Boolean useSecureCookie = new Boolean(false);
        final int expiryTime = liveSeconds;
        final String cookiePath = "/";

        Cookie cookie = new Cookie(cookieName, ObjectToJson(value));
        cookie.setSecure(useSecureCookie.booleanValue());  // determines whether the cookie should only be sent using a secure protocol, such as HTTPS or SSL
        cookie.setMaxAge(expiryTime);  // A negative value means that the cookie is not stored persistently and will be deleted when the Web browser exits. A zero value causes the cookie to be deleted.
        cookie.setPath(cookiePath);  // The cookie is visible to all the pages in the directory you specify, and all the pages in that directory's subdirectories
        response.addCookie(cookie);
    }

    /**
     * 取完整的URL
     * @param req
     * @return
     */
    public static String getFullUrl(HttpServletRequest req) {
        String reqUrl = req.getRequestURL().toString();
        String queryString = req.getQueryString();
        if (queryString != null) {
            reqUrl += "?"+queryString;
        }
        return reqUrl;
    }

    /***
     * 是否老版本的浏览器
     * @param
     * @return
     */
    public static boolean isOldBrowser(){
        String ua=getRequest().getHeader("User-Agent");
        return oldBrowser.matcher(ua).find();
    }

    /**
     * 取对象的json格式
     * @param obj
     * @return
     */
    public static String ObjectToJson(Object obj){
        String ret=null;
        ObjectMapper mapper = new ObjectMapper();
        try {

            SimpleModule simpleModule = new SimpleModule("SimpleModule",
                    new Version(1,1,0,null));
            simpleModule.addSerializer(BigInteger.class, new BigIntegerSerializerProvider());
            simpleModule.addSerializer(Long.class, new LongSerializerProvider());
            simpleModule.addSerializer(Long.TYPE, new LongSerializerProvider());
            simpleModule.addSerializer(Date.class, new DateSerializerProvider());
            mapper.registerModule(simpleModule);


            ret = mapper.writeValueAsString(obj);
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }


    @SuppressWarnings({ "unchecked"})
    public static Hashtable<String, Object> jsonToMap(String json){
        Hashtable<String, Object> ret=new Hashtable<String, Object>();
        ObjectMapper mapper = new ObjectMapper();
        try {
            ret=mapper.readValue(json, ret.getClass());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }


    /**
     * 将键值交替的数组转换成JSON字符串
     * @param keyAndValue 参数：键，值，键，值......
     * @return
     */
    public static String KeyValueToJson(Object...keyAndValue){
        Hashtable<String, Object> data=new Hashtable<String, Object>();
        for(int i=0; i<keyAndValue.length/2; i++){
            data.put(keyAndValue[i*2].toString(), keyAndValue[i*2+1]);
        }
        return ObjectToJson(data);
    }

    /**
     * 密码的MD5编码
     * @param src
     * @return
     */
    public static String passwordMd5(String src){
        Md5PasswordEncoder md5 = new Md5PasswordEncoder();
        md5.setEncodeHashAsBase64(false);
        return md5.encodePassword(src, null);
    }

    /**
     * 字符串的MD5编码
     * @param src
     * @return
     */
    public static String md5(String src){
        String ret=null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(src.getBytes());
            byte[] byteData = md.digest();
            StringBuffer sb=new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
                sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
            }
            ret=sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 字符串转换为十六进制表示
     * @param text
     * @return
     */
    public static String str2Hex(String str){
        byte[] bytes=str.getBytes();
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<bytes.length;i++){
            String hex=Integer.toHexString(bytes[i]);
            sb.append(hex.substring(hex.length()-2, hex.length()));
        }
        return sb.toString();
    }

    /**
     * 转换十六进制未字符串
     * @param hex
     * @return
     */
    public static String hex2Str(String hex){
        byte[] bytes=new byte[hex.length()/2];
        for(int i=0;i<bytes.length;i++){
            bytes[i]=(byte)Integer.parseInt(hex.substring(i*2,  i*2+2), 16);
        }
        return new String(bytes);
    }

    /**
     * 取系统启动时间（毫秒）
     * @return
     */
    public static long getUpTime(){
        RuntimeMXBean mxBean = ManagementFactory.getRuntimeMXBean();
        return mxBean.getUptime();
    }


    public static void main(String[] args){
        String s=str2Hex("");
        System.out.println(s);
        String s2=hex2Str(s);
        System.out.println(s2);
    }


    /**
     * 发送文件给浏览器
     * @param path
     * @param alternativePath
     * @param response
     * @throws IOException
     */
    public static void sendFile(String path, String alternativePath, HttpServletResponse response) throws IOException{
        File file=new File(path);
        if(file.exists()){
            BufferedInputStream in=new BufferedInputStream(new FileInputStream(file));
            try{
                StreamUtils.copy(in , response.getOutputStream());
                response.flushBuffer();
            }finally{
                in.close();
            }
        }else{
            response.sendRedirect(alternativePath);
        }
    }

    /**
     * 取客户端地址
     * @return
     */
    public static String remoteAddr(){
        String ret=null;
        HttpServletRequest request=getRequest();
        ret=request.getHeader("x-real-ip");
        if(ret==null){
            ret=request.getRemoteAddr();
        }
        return ret;
    }

    /**
     * 把json字符串转换为扁平化的map（不分层次，只取最里层）
     * @param json
     * @return
     */
    public static Hashtable<String, String> jsonToFlatMap(String json){
        Hashtable<String, String> ret=new Hashtable<String, String>();
        Matcher m=pKeyVal.matcher(json);
        while (m.find()) {
            ret.put(m.group(2), m.group(5));
        }
        return ret;
    }


}
